
local Layout = commonlib.inherit(commonlib.ToolBase);

Layout:Property("Element");
Layout:Property("BorderBox", false, "IsBorderBox");                -- 区域盒子

Layout:Property("RelativeLayout", false);                          -- 相对布局对象

Layout:Property("BoxLayout", false, "IsBoxLayout");                -- 是否盒子布局
Layout:Property("FlexLayout", false, "IsFlexLayout");              -- 是否弹性布局
Layout:Property("NoneLayout", true, "IsNoneLayout");               -- 是否无布局

Layout:Property("BlockElement", false, "IsBlockElement");                        -- 是否块元素
Layout:Property("InlineElement", false, "IsInlineElement");                      -- 是否内联元素
Layout:Property("FlexElement", false, "IsFlexElement");                          -- 是否弹性元素
Layout:Property("PositionElement", false, "IsPositionElement");                  -- 是否是定位元素
Layout:Property("AbsoluteElement", false, "IsAbsoluteElement");                  -- 是否是绝对定位元素
Layout:Property("FixedElement", false, "IsFixedElement");                        -- 是否是固定定位元素

Layout:Property("UseSpace", true, "IsUseSpace");                   -- 是否使用空间
Layout:Property("Visible", true, "IsVisible");                     -- 是否可见

function Layout:ctor()
end

function Layout:Init(element)
    self:SetElement(element);
    self:Reset();

    return self;
end

-- 重置布局
function Layout:Reset()
	-- 相对自己定位的布局列表
	self.relative_position_layouts = {};

	-- 元素宽高 
	self.x, self.y, self.width, self.height = 0, 0, 0, 0;
	-- 真实内容宽高
	self.realContentWidth, self.realContentHeight = 0, 0;
	-- 内容宽高
	self.contentWidth, self.contentHeight = 0, 0;  
	-- 空间大小
	self.spaceWidth, self.spaceHeight = 0, 0;
	-- 边框
	self.borderTop, self.borderRight, self.borderBottom, self.borderLeft = 0, 0, 0, 0;
	-- 填充
	self.paddingTop, self.paddingRight, self.paddingBottom, self.paddingLeft = 0, 0, 0, 0;
	-- 边距
    self.marginTop, self.marginRight, self.marginBottom, self.marginLeft = 0, 0, 0, 0;
    
	-- 是否固定内容大小
    self:SetUseSpace(true);

	self:SetInlineElement(false);
    self:SetBlockElement(false);
    self:SetFlexElement(false);
    self:SetPositionElement(false);
	self:SetFixedElement(false);

	self:SetNoneLayout(true);
	self:SetBoxLayout(false);
	self:SetFlexLayout(false);

	self:SetRelativeLayout(nil);
end

-- 遍历
function Layout:ForEachChildren(callback, filter)
	local filter_type = type(filter);
	for child in self:GetElement():ChildrenIterator() do
		local child_layout = child:GetLayout();
		if (filter_type == "function") then
			if (filter(child_layout, child)) then callback(child_layout, child) end 
		else
			if ((not child_layout:IsNoneLayout()) and child_layout:IsUseSpace() and child:IsExist()) then callback(child_layout, child) end 
		end
	end
end

-- 获取元素样式
function Layout:GetElementStyle()
	return self:GetElement():GetCurrentStyle();
end

-- 获取父布局
function Layout:GetParentLayout()
    local parent = self:GetElement():GetParent();
    return parent and parent:GetLayout();
end

-- 获取根布局
function Layout:GetRootLayout()
    return self:GetWindow() and self:GetWindow():GetLayout();
end

-- 是否是窗口
function Layout:IsWindowElement()
	return self:GetWindow() == self:GetElement();
end

-- 获取属性ID
function Layout:GetAttrId()
	return self:GetElement():GetAttrStringValue("id");
end

function Layout:GetTagNameAndName()
	return self:GetTagName() .. "-" .. self:GetName();
end

-- 获取元素名
function Layout:GetName()
	return self:GetElement():GetName();
end

-- 获取元素名
function Layout:GetTagName()
    return self:GetElement():GetTagName();
end

-- 获取窗口
function Layout:GetWindow()
    return self:GetElement():GetWindow();
end

-- 获取窗口位置 x, y, w, h    (w, h 为宽高, 非坐标)
function Layout:GetWindowPosition()
	return self:GetWindow():GetWindowPosition();
end
-- 设置空间大小
function Layout:SetSpaceWidthHeight(width, height)
	self.spaceWidth, self.spaceHeight = width, height;
end
-- 获取空间大小 margin border padding content
function Layout:GetSpaceWidthHeight(width, height)
	return self.spaceWidth, self.spaceHeight;
end
-- 设置区域宽高 
function Layout:SetWidthHeight(width, height)
	self.width, self.height = width, height;
	local marginTop, marginRight, marginBottom, marginLeft = self:GetMargin();
	local paddingTop, paddingRight, paddingBottom, paddingLeft = self:GetPadding();
	local borderTop, borderRight, borderBottom, borderLeft = self:GetBorder();
	self.spaceWidth = width and (width + marginLeft + marginRight);
	self.spaceHeight = height and (height + marginTop + marginBottom);
	self.contentWidth = width and (width - borderLeft - borderRight - paddingLeft - paddingRight);
	self.contentHeight = height and (height - borderTop - borderBottom - paddingTop - paddingBottom);
end
-- 获取区域宽高 
function Layout:GetWidthHeight()
	return self.width, self.height;
end
-- 获取内容偏移
function Layout:GetContentOffset()
	return self.borderLeft + self.paddingLeft, self.borderTop + self.paddingTop;
end
-- 获取内容位置
function Layout:GetContentPos()
	return self.x + self.borderLeft + self.paddingLeft, self.y + self.borderTop + self.paddingTop;
end
-- 设置内容宽高
function Layout:SetContentWidthHeight(width, height)
    self.contentWidth, self.contentHeight = width, height;
end
-- 获取元素边界
function Layout:GetSpacePos()
	return self.x - self.marginLeft, self.y - self.marginTop;
end
-- 获取内容宽高 
function Layout:GetContentWidthHeight()
	return self.contentWidth, self.contentHeight;
end
-- 设置真实宽高
function Layout:SetRealContentWidthHeight(width, height)
    self.realContentWidth, self.realContentHeight = width, height;
end
-- 获取真实宽高 
function Layout:GetRealContentWidthHeight()
	return self.realContentWidth, self.realContentHeight;
end
-- 设置最小宽高 
function Layout:SetMinWidthHeight(width, height)
	self.minWidth, self.minHeight = width, height;
end
-- 获取最小宽高
function Layout:GetMinWidthHeight()
	return self.minWidth, self.minHeight;
end
-- 设置最大宽高 
function Layout:SetMaxWidthHeight(width, height)
	self.maxWidth, self.maxHeight = width, height;
end
-- 获取最大宽高
function Layout:GetMaxWidthHeight()
	return self.maxWidth, self.maxHeight;
end
-- 设置填充
function Layout:SetBorder(top, right, bottom, left)
    self.borderTop, self.borderRight, self.borderBottom, self.borderLeft = top, right, bottom, left;
end
-- 获取填充 top right bottom left 
function Layout:GetBorder()
	return self.borderTop, self.borderRight, self.borderBottom, self.borderLeft;
end
-- 设置填充
function Layout:SetPadding(top, right, bottom, left)
    self.paddingTop, self.paddingRight, self.paddingBottom, self.paddingLeft = top, right, bottom, left;
end
-- 获取填充 top right bottom left 
function Layout:GetPadding()
	return self.paddingTop, self.paddingRight, self.paddingBottom, self.paddingLeft;
end
-- 设置边距
function Layout:SetMargin(top, right, bottom, left)
    self.marginTop, self.marginRight, self.marginBottom, self.marginLeft = top, right, bottom, left;
end
-- 获取填充 top right bottom left 
function Layout:GetMargin()
	return self.marginTop, self.marginRight, self.marginBottom, self.marginLeft;
end
-- 设置位置坐标
function Layout:SetPos(x, y)
	self.x, self.y = x or 0, y or 0;
end
-- 获取位置坐标
function Layout:GetPos()
	return self.x or 0, self.y or 0; 
end
-- 设置元素z轴序
function Layout:SetZIndex(zindex)
	self:GetElement():SetZIndex(zindex);
end

-- 百分比转数字
function Layout:PercentageToNumber(percentage, size)
	if (percentage == nil or type(percentage) == "number") then return percentage end
	if (type(percentage) == "string" and (string.match(percentage, "%%$"))) then
		if (size) then
			percentage = tonumber(string.match(percentage, "[%+%-]?%d+"));
			return math.floor(size * percentage /100);
		else
			return nil;
		end
	end
	print("ERROR: Invalid Dimension", percentage);
	return nil;
end

-- 是否裁剪溢出
function Layout:IsClipOverflow()
	return self.overflowX == "auto" or self.overflowX == "scroll" or self.overflowX == "hidden" or self.overflowY == "auto" or self.overflowY == "scroll" or self.overflowY == "hidden";
end

-- X方向是否允许滚动
function Layout:IsEnableScrollX()
	return self.overflowX == "auto" or self.overflowX == "scroll";
end

-- Y方向是否允许滚动
function Layout:IsEnableScrollY()
	return self.overflowY == "auto" or self.overflowY == "scroll";
end

-- 是否允许滚动
function Layout:IsEnableScroll()
	return self:IsEnableScrollX() or self:IsEnableScrollY();
end

-- 是否溢出
function Layout:IsOverflow()
	return self:IsOverflowX() or self:IsOverflowY();
end

-- X方向是否溢出
function Layout:IsOverflowX()
	return self.contentWidth and self.realContentWidth and self.realContentWidth > self.contentWidth;
end

-- Y方向是否溢出
function Layout:IsOverflowY()
	return self.contentHeight and self.realContentHeight and self.realContentHeight > self.contentHeight;
end

-- 是否可以滚动
function Layout:IsCanScroll()
	return self:IsCanScrollX() or self:IsCanScrollY();
end

-- X方向是否可以滚动
function Layout:IsCanScrollX()
	return self:IsEnableScrollX() and self:IsOverflowX();
end

-- Y方向是否可以滚动
function Layout:IsCanScrollY()
	return self:IsEnableScrollY() and self:IsOverflowY();
end

function Layout:OnBegin()
    self:Reset();

    local style = self:GetElementStyle();
    local display = style.display or "block";
	local position = style.position or "static";
	local visibility = style.visibility;

	-- 设置盒子类型
	if (style["box-sizing"] == "border-box") then
		self:SetBorderBox(true);
	else  -- content-box
		self:SetBorderBox(false);  -- 默认都是内容盒子
	end

    -- 块元素
    if (display ~= "inline" and display ~= "inline-block" and display ~= "inline-flex" and not style.float) then 
		self:SetBlockElement(true);
	else 
		self:SetInlineElement(true);
	end
	
	-- 布局
	if (display == "flex" or display == "inline-flex") then 
		self:SetFlexElement(true);
		self:SetFlexLayout(true);
	else
		self:SetBoxLayout(true)
	end

	if (display == "none") then 
		self:SetNoneLayout(true);
	else 
		self:SetNoneLayout(false);
	end
	
	-- 是否可见
    if (display == "none" or visibility == "hidden") then 
        self:SetVisible(false);
    else
        self:SetVisible(true);
    end

	if (position == "absolute" or position == "fixed") then 
		self:SetPositionElement(true);
		self:SetUseSpace(false);                   -- 不使用文档流
		self:SetZIndex(style["z-index"] or 1)      -- 定位元素默认为1
		if (position == "absolute") then
			self:SetAbsoluteElement(true);
			self:SetRelativeLayout(self:GetParentLayout());
		elseif (position == "fixed") then
			self:SetFixedElement(true);
			self:SetRelativeLayout(self:GetRootLayout());
		end
		if (self:GetRelativeLayout()) then
			table.insert(self:GetRelativeLayout().relative_position_layouts, self);    -- 添加相对布局的定位列表
		end
	else
		self:SetUseSpace(true);
		self:SetPositionElement(false);
		self:SetZIndex(style["z-index"] or 0);     -- 普通元素默认为0
	end
	
    -- 溢出
    self.overflowX = style["overflow-x"] or "visible";
	self.overflowY = style["overflow-y"] or "visible";
	self.float = style.float;

	-- 是窗口根元素
	if (self:IsWindowElement())	then
		local winX, winY, winWidth, winHeight = self:GetElement():GetWindowPosition();
		self:SetPos(0, 0);
		self:SetWidthHeight(winWidth, winHeight);
		return;
	end
    
    -- 获取父元素内容宽高 百分比统一使用内容宽高
    local parentLayout = self:GetParentLayout();
	local parentContentWidth, parentContentHeight = nil, nil;
    if (parentLayout) then
		if (self:IsPositionElement()) then 
			parentLayout = self:GetRelativeLayout() or parentLayout;
			parentContentWidth, parentContentHeight = parentLayout:GetWidthHeight();
		else 
			parentContentWidth, parentContentHeight = parentLayout:GetContentWidthHeight();
		end
	else 
		local winX, winY, winWidth, winHeight = self:GetWindowPosition();
		parentContentWidth, parentContentHeight = winWidth, winHeight;
    end

	-- 数字最大最小宽高
	local minWidth, minHeight, maxWidth, maxHeight = style["min-width"], style["min-height"], style["max-width"], style["max-height"];
	minWidth = self:PercentageToNumber(minWidth, parentContentWidth);
	maxWidth = self:PercentageToNumber(maxWidth, parentContentWidth);
	minHeight = self:PercentageToNumber(minHeight, parentContentHeight);
	maxHeight = self:PercentageToNumber(maxHeight, parentContentHeight);
	self:SetMinWidthHeight(minWidth, minHeight);
	self:SetMaxWidthHeight(maxWidth, maxHeight);

	-- 数字化边距
	local marginTop, marginRight, marginBottom, marginLeft = style["margin-top"], style["margin-right"], style["margin-bottom"], style["margin-left"];
	marginTop = self:PercentageToNumber(marginTop, parentContentHeight) or 0;
	marginRight = self:PercentageToNumber(marginRight, parentContentWidth) or 0;
	marginBottom = self:PercentageToNumber(marginBottom, parentContentHeight) or 0;
	marginLeft = self:PercentageToNumber(marginLeft, parentContentWidth) or 0;
	self:SetMargin(marginTop, marginRight, marginBottom, marginLeft);
	
	-- 数字化边框
	local borderTop, borderRight, borderBottom, borderLeft = style["border-top-width"], style["border-right-width"], style["border-bottom-width"], style["border-left-width"];
	borderTop = self:PercentageToNumber(borderTop, parentContentHeight) or 0;
	borderRight = self:PercentageToNumber(borderRight, parentContentWidth) or 0;
	borderBottom = self:PercentageToNumber(borderBottom, parentContentHeight) or 0;
	borderLeft = self:PercentageToNumber(borderLeft, parentContentWidth) or 0;
	self:SetBorder(borderTop, borderRight, borderBottom, borderLeft);

	-- 数字化填充
	local paddingTop, paddingRight, paddingBottom, paddingLeft = style["padding-top"], style["padding-right"], style["padding-bottom"], style["padding-left"];
	paddingTop = self:PercentageToNumber(paddingTop, parentContentHeight) or 0;
	paddingRight = self:PercentageToNumber(paddingRight, parentContentWidth) or 0;
	paddingBottom = self:PercentageToNumber(paddingBottom, parentContentHeight) or 0;
	paddingLeft = self:PercentageToNumber(paddingLeft, parentContentWidth) or 0;
	self:SetPadding(paddingTop, paddingRight, paddingBottom, paddingLeft);

	-- 数字化宽高
	local width, height = style.width, style.height;     
	if (self:IsPositionElement()) then
		-- 定位位置
		local left, top, right, bottom = style.left, style.top, style.right, style.bottom;
		top = self:PercentageToNumber(top, parentContentHeight);
		right = self:PercentageToNumber(right, parentContentWidth);
		bottom = self:PercentageToNumber(bottom, parentContentHeight);
		left = self:PercentageToNumber(left, parentContentWidth);
	
		if (right and width and not left) then left = parentContentWidth - right - width end
		if (bottom and height and not top) then top = parentContentHeight - bottom - height end
		if (not width and left and right) then width = parentContentWidth - left - right end 
		if (not height and top and bottom) then height = parentContentHeight - top - bottom end 

		self:SetPos(left or 0, top or 0);
	else 
		width, height = width or "100%", height or "100%";		
	end
	width = self:PercentageToNumber(width, parentContentWidth) or 0;
	height = self:PercentageToNumber(height, parentContentHeight) or 0;
	width, height = math.min(width, maxWidth or width), math.min(height, maxHeight or height);
	width, height = math.max(width, minWidth or width), math.max(height, minHeight or height);

	if (self:IsBorderBox()) then
		self:SetWidthHeight(width, height);
	else
		self:SetWidthHeight(width and (width + paddingLeft + paddingRight + borderLeft + borderRight), height and (height + paddingTop + paddingBottom + borderTop + borderBottom));
	end
	-- print_if(self:GetAttrId(), string.format("Layout:OnBegin id = %s, width = %s, height = %s", self:GetAttrId(), width, height));
end

function Layout:OnBeforeUpdateChildrenLayout()
end

-- 更新布局, 在子元素完成布局和位置调整后执行, 完成对自身大小的确定
function Layout:OnUpdateLayout()
	return self;
end

-- 子元素布局完成, 调整子元素位置和真实宽高
function Layout:OnAfterUpdateChildrenLayout()
	self:BoxLayoutAdjustChildrenPosition();
	self:FlexLayoutAdjustChildrenPosition();
end

-- 结束布局, 更新元素的窗口位置
function Layout:OnEnd()
end

-- 元素布局完成 宽高已确定 需要再去确定父布局是否需要调整子元素的位置
function Layout:OnAfterUpdateLayout()
end

function Layout:BoxLayoutAdjustChildrenPosition()
	if (not self:IsBoxLayout()) then return end 

	local availableX, availableY, rightAvailableX, rightAvailableY, realContentWidth, realContentHeight = 0, 0, 0, 0, 0, 0;
	local width, height = self:GetWidthHeight();
	local element = self:GetElement();

	-- print_if(self:GetAttrId(), string.format("Layout:BoxLayoutAdjustChildrenPosition id = %s, width = %s, height = %s", layout:GetAttrId(), width, height), availableX, availableY);

	-- 渲染序
	self:ForEachChildren(function(childLayout, childElement)
		local childLeft, childTop = 0, 0;
		local childMarginTop, childMarginRight, childMarginBottom, childMarginLeft = childLayout:GetMargin();
		local childSpaceWidth, childSpaceHeight = childLayout:GetSpaceWidthHeight();
		local childWidth, childHeight = childLayout:GetWidthHeight();
		local isRightFloat = childLayout.float == "right";

		if (not childLayout:IsNoneLayout() and childLayout:IsUseSpace()) then
			-- print_if(layout:GetAttrId() == "1" or childLayout:GetAttrId(),
			-- 	string.format("\nid = %s parent_id = %s ", childLayout:GetAttrId(), layout:GetAttrId()),
			-- 	string.format("\nParent Layout availableX = %s, availableY = %s, realContentWidth = %s, realContentHeight = %s, width = %s, height = %s", availableX, availableY, realContentWidth, realContentHeight, width, height),
			-- 	-- string.format("child margin: %s, %s, %s, %s", childMarginTop, childMarginRight, childMarginBottom, childMarginLeft), childStyle,
			-- 	string.format("\nLayout childLeft = %s, childTop = %s, childSpaceWidth = %s, childSpaceHeight = %s, childWidth = %s, childHeight = %s", childLeft, childTop, childSpaceWidth, childSpaceHeight, childWidth, childHeight)
			-- );
			if (childLayout:IsInlineElement()) then
				-- 内联元素
				-- print(childLayout:GetAttrId(), childLayout:GetTagNameAndName(), width, availableX, rightAvailableX, childSpaceWidth);
				if ((width - availableX - rightAvailableX) < childSpaceWidth) then
					-- 新起一行
					if (isRightFloat) then
						childLeft, childTop = (width - childSpaceWidth + childMarginLeft), realContentHeight + childMarginTop;
						availableX, availableY = 0, realContentHeight;
						rightAvailableX, rightAvailableY = childSpaceWidth, realContentHeight;
					else
						childLeft, childTop = childMarginLeft, realContentHeight + childMarginTop;
						availableX, availableY = childSpaceWidth, realContentHeight;
						rightAvailableX, rightAvailableY = 0, realContentHeight;
					end
				else 
					-- 同行追加
					if (isRightFloat) then
						childLeft, childTop = (width - rightAvailableX - childSpaceWidth + childMarginLeft), rightAvailableY + childMarginTop;
						availableX, availableY = availableX, availableY;
						rightAvailableX, rightAvailableY = rightAvailableX + childSpaceWidth, rightAvailableY;
					else
						childLeft, childTop = availableX + childMarginLeft, availableY + childMarginTop;
						availableX, availableY = availableX + childSpaceWidth, availableY;
						rightAvailableX, rightAvailableY = rightAvailableX, rightAvailableY;
					end
				end
				realContentWidth = commonlib.if_else(realContentWidth > (availableX + rightAvailableX), realContentWidth, availableX + rightAvailableX);
				local newHeight = availableY + childSpaceHeight;
				realContentHeight = commonlib.if_else(newHeight > realContentHeight, newHeight, realContentHeight)
			else 
				-- 块元素 新起一行
				childLeft, childTop = childMarginLeft, realContentHeight + childMarginTop;
				availableX, availableY = 0, realContentHeight + childSpaceHeight;    -- 可用位置X坐标置0 取最大Y坐标
				rightAvailableX, rightAvailableY = availableX, availableY;
				realContentWidth = commonlib.if_else(childSpaceWidth > realContentWidth, childSpaceWidth, realContentWidth);
				realContentHeight = availableY;
			end
			childLayout:SetPos(childLeft, childTop);
			-- print_if(
			-- 	element:GetAttrValue("id") == "debug",
			-- 	string.format("[%s] Layout Add ChildLayout After ", layout:GetTagNameAndName()),
			-- 	string.format("Layout availableX = %s, availableY = %s, realContentWidth = %s, realContentHeight = %s, width = %s, height = %s", availableX, availableY, realContentWidth, realContentHeight, width, height),
			-- 	string.format("[%s] childLeft = %s, childTop = %s, childSpaceWidth = %s, childSpaceHeight = %s", childLayout:GetTagNameAndName(), childLeft, childTop, childSpaceWidth, childSpaceHeight)
			-- );
		end
	end);
	local paddingTop, paddingRight, paddingBottom, paddingLeft = self:GetPadding();
	local borderTop, borderRight, borderBottom, borderLeft = self:GetBorder();
	-- print_if(
	-- 	element:GetAttrValue("id") == "debug",
	-- 	string.format("children count = %s, TagName = %s", #element.childrens, layout:GetTagNameAndName()),
	-- 	string.format("paddingTop = %s, paddingRight = %s, paddingBottom = %s, paddingLeft = %s, borderTop = %s, borderRight = %s, borderBottom = %s, borderLeft = %s", paddingTop, paddingRight, paddingBottom, paddingLeft, borderTop, borderRight, borderBottom, borderLeft)
	-- );

	-- 假宽度右浮动元素需要调整
	for child in element:ChildrenIterator() do
		local childLayout, childStyle = child:GetLayout(), child:GetStyle(); 
		if (not childLayout:IsPositionElement()) then
			local left, top = childLayout:GetPos();
			if (childStyle.float == "right") then
				left = left - paddingRight - borderRight;
			else
				left = left + paddingLeft + borderLeft;
			end
			top = top + paddingTop + borderTop;
			childLayout:SetPos(left, top);
			-- print_if(child:GetAttrValue("id"), string.format("Layout:OnAfterUpdateChildrenLayout id = %s Pos x = %s, y = %s", child:GetAttrValue("id"), left, top));
		else 

		end
	end

	-- 设置内容宽高
	-- print_if(element:GetAttrValue("id"), string.format("Layout:OnAfterUpdateChildrenLayout id = %s realContentWidth = %s, realContentHeight = %s", element:GetAttrValue("id"), realContentWidth, realContentHeight));
	self:SetRealContentWidthHeight(realContentWidth, realContentHeight);
end

function Layout:FlexLayoutAdjustChildrenPosition()
    if (not self:IsFlexLayout()) then return end 
    local style = self:GetElementStyle();
	local flex_direction = style["flex-direction"] or "row";
    if (flex_direction == "row" or flex_direction == "row-reverse") then
        self:FlexLayoutAdjustRowChildrenPosition();
    end

    if (flex_direction == "column" or flex_direction == "column-reverse") then
        self:FlexLayoutAdjustColChildrenPosition();
    end
end

local function RelayoutChildrenElement(element, relayoutReason)
	for child in element:ChildElementIterator(true, LayoutElementFilter) do
		local childLayout = element:GetLayout();
		-- 元素宽度改变而子元素非固定宽度
		if (relayoutReason == "width_change" and not childLayout:IsFixedWidth()) then child:UpdateLayout() end
		if (relayoutReason == "height_change" and not childLayout:IsFixedHeight()) then child:UpdateLayout() end
	end
end 

function Layout:FlexLayoutAdjustRowChildrenPosition()
    local style = self:GetElementStyle();
	local contentOffsetX, contentOffsetY = self:GetContentOffset();
    local width, height = self:GetContentWidthHeight();
	local lines, line = {}, {layouts = {}, width = 0, height = 0, flexGrow = 0};
	table.insert(lines, line);
    
	self:ForEachChildren(function(childLayout, childElement)
		local childSpaceWidth, childSpaceHeight = childLayout:GetSpaceWidthHeight();
        local childStyle = childLayout:GetElementStyle();

		if (width and (line.width + childSpaceWidth) > width) then
			line = {layouts = {}, width = 0, height = 0, flexGrow = 0};
			table.insert(lines, line);
		end

		line.flexGrow = line.flexGrow + (childStyle["flex-grow"] or 0);
		line.width = line.width + childSpaceWidth;
		line.height = math.max(line.height, childSpaceHeight);
		table.insert(line.layouts, childLayout);
    end)

	-- local totalHeight = 0;
    local offsetLeft, offsetTop, HGap, VGap = 0, 0, 0, 0;
    local contentWidth, contentHeight = 0, 0;
    local function UpdateChildLayoutPos(line)
        for _, childLayout in ipairs(line.layouts) do
			local spaceWidth, spaceHeight = childLayout:GetSpaceWidthHeight();
			local childMarginTop, childMarginRight, childMarginBottom, childMarginLeft = childLayout:GetMargin();
			local alignSelf = childLayout:GetElementStyle()["align-self"];
			local lineHeight = line.height;
			if (alignSelf == "center") then
				childLayout:SetPos(contentOffsetX + offsetLeft + childMarginLeft, contentOffsetY + offsetTop + childMarginTop + (lineHeight - spaceHeight) / 2);
			elseif (alignSelf == "flex-end") then
				childLayout:SetPos(contentOffsetX + offsetLeft + childMarginLeft, contentOffsetY + offsetTop + childMarginTop + lineHeight - spaceHeight);
			else
				childLayout:SetPos(contentOffsetX + offsetLeft + childMarginLeft, contentOffsetY + offsetTop + childMarginTop);
			end
			-- FlexDebug.Format("child layout left = %s, top = %s, spaceWidth = %s, hgap = %s, count = %s", offsetLeft, offsetTop, spaceWidth, HGap, #line.layouts);
            offsetLeft = offsetLeft + spaceWidth + HGap;
        end
    end

    if (height) then
        local totalHeight = 0;
        for _, line in ipairs(lines) do totalHeight = totalHeight + line.height end
        local remainHeight = height - totalHeight;
        if (style["align-items"] == "center") then 
            offsetTop = remainHeight / 2; 
        elseif (style["align-items"] == "flex-end") then 
            offsetTop = remainHeight; 
        elseif (style["align-items"] == "space-between") then 
            local gapCount = #(line.layouts) - 1;
            if (gapCount > 0) then VGap = remainHeight / gapCount end
        elseif (style["align-items"] == "space-around") then 
            local gapCount = #(line.layouts) + 1;
            VGap = remainHeight / gapCount;
            offsetTop = VGap;
        end 
    end
	-- FlexDebug(lines);
	for no, line in ipairs(lines) do
		if (width) then
			local remainWidth = width - line.width;
			if (line.flexGrow > 0) then
				for _, childLayout in ipairs(line.layouts) do
					childLayout:SetPos(contentOffsetX + offsetLeft, contentOffsetY + offsetTop);
					local spaceWidth = childLayout:GetSpaceWidthHeight();
					local flexGrow = childLayout:GetElementStyle()["flex-grow"] or 0;
					if (flexGrow == 0) then
						offsetLeft = offsetLeft + spaceWidth;
					else 
						local autoWidth= remainWidth * flexGrow / line.flexGrow;
						offsetLeft = offsetLeft + spaceWidth + autoWidth;
						local width, height = childLayout:GetWidthHeight();
						childLayout:SetWidthHeight(width + autoWidth, height); 
						-- 是否重新更新子布局
						-- if (autoWidth ~= 0) then RelayoutChildrenElement(childLayout:GetElement(), "width_change") end
					end
				end
			else
                if (style["justify-content"] == "center") then 
                    offsetLeft = remainWidth / 2; 
                elseif (style["justify-content"] == "flex-end") then 
                    offsetLeft = remainWidth; 
				elseif (style["justify-content"] == "space-between") then 
					local gapCount = #(line.layouts) - 1;
					if (gapCount > 0) then HGap = remainWidth / gapCount end
                elseif (style["justify-content"] == "space-around") then 
					local gapCount = #(line.layouts) + 1;
					HGap = remainWidth / gapCount;
					offsetLeft = HGap;
				end 
				-- FlexDebug.Format("no = %s, hgap = %s, contentWidth = %s, width = %s, count = %s", no, HGap, line.width, width, #line.layouts);
				UpdateChildLayoutPos(line);
			end
		else 
			UpdateChildLayoutPos(line);
		end
        contentWidth = math.max(contentWidth, offsetLeft - (style["justify-content"] == "space-around" and HGap or 0));
		offsetLeft, HGap = 0, 0;
        offsetTop = offsetTop + line.height + VGap;
        contentHeight = math.max(contentHeight, offsetTop - (style["align-items"] == "space-around" and VGap or 0));
	end

	-- FlexDebug.Format("left = %s, top = %s, width = %s, height = %s, contentWidth = %s, contentHeight = %s", left, top, width, height, contentWidth, contentHeight);
    self:SetRealContentWidthHeight(contentWidth, contentHeight);
end


function Layout:FlexLayoutAdjustColChildrenPosition()
    local style = self:GetElementStyle();
	local contentOffsetX, contentOffsetY = self:GetContentOffset();
	local width, height = self:GetContentWidthHeight();
	local lines, line = {}, {layouts = {}, width = 0, height = 0, flexGrow = 0};
	-- print(string.format("FlexLayoutAdjustChildrenPosition:UpdateCol left = %s, top = %s, width = %s, height = %s", left, top, width, height));
	table.insert(lines, line);
    self:ForEachChildren(function(childLayout, childElement)
        local childStyle = childLayout:GetElementStyle();
		local childSpaceWidth, childSpaceHeight = childLayout:GetSpaceWidthHeight();

		if (height and (line.height + childSpaceHeight) > height) then
			line = {layouts = {}, width = 0, height = 0, flexGrow = 0};
			table.insert(lines, line);
		end

		line.flexGrow = line.flexGrow + (childStyle["flex-grow"] or 0);
		line.height = line.height + childSpaceHeight;
		line.width = math.max(line.width, childSpaceWidth);
		table.insert(line.layouts, childLayout);
		-- FlexDebug.Format("childSpaceWidth = %s, childSpaceHeight = %s, width = %s, height = %s, childCount = %s", childSpaceWidth, childSpaceHeight, width, height, #line.layouts);
    end)

	-- local totalHeight = 0;
    local offsetLeft, offsetTop, HGap, VGap = 0, 0, 0, 0;
    local contentWidth, contentHeight = 0, 0;
    local function UpdateChildLayoutPos(line)
        for _, childLayout in ipairs(line.layouts) do
			local spaceWidth, spaceHeight = childLayout:GetSpaceWidthHeight();
			local childMarginTop, childMarginRight, childMarginBottom, childMarginLeft = childLayout:GetMargin();
			local alignSelf = childLayout:GetElementStyle()["align-self"];
			local lineWidth = line.width;
			if (alignSelf == "center") then
				childLayout:SetPos(contentOffsetX + offsetLeft + childMarginLeft + (lineWidth - spaceWidth) / 2, contentOffsetY + offsetTop + childMarginTop);
			elseif (alignSelf == "flex-end") then
				childLayout:SetPos(contentOffsetX + offsetLeft + childMarginLeft + lineWidth - spaceWidth, contentOffsetY + offsetTop + childMarginTop);
			else
				childLayout:SetPos(contentOffsetX + offsetLeft + childMarginLeft, contentOffsetY + offsetTop + childMarginTop);
			end
			offsetTop = offsetTop + spaceHeight + VGap;
			-- FlexDebug.Format("child layout left = %s, top = %s, spaceHeight = %s, vgap = %s, count = %s", offsetLeft, offsetTop, spaceHeight, VGap, #line.layouts);
        end
    end

    if (width) then
        local totalWidth = 0;
        for _, line in ipairs(lines) do totalWidth = totalWidth + line.width end
        local remainWidth = width - totalWidth;
        if (style["align-items"] == "center") then 
            offsetLeft = remainWidth / 2; 
        elseif (style["align-items"] == "flex-end") then 
            offsetLeft = remainWidth; 
        elseif (style["align-items"] == "space-between") then 
            local gapCount = #(line.layouts) - 1;
            if (gapCount > 0) then HGap = remainWidth / gapCount end
        elseif (style["align-items"] == "space-around") then 
            local gapCount = #(line.layouts) + 1;
            HGap = remainWidth / gapCount;
            offsetLeft = HGap;
        end 
    end
    
	for _, line in ipairs(lines) do
		if (height) then
			local remainHeight = height - line.height;
			if (line.flexGrow > 0) then
				for _, childLayout in ipairs(line.layouts) do
					childLayout:SetPos(contentOffsetX + offsetLeft, contentOffsetY + offsetTop);
					local spaceWidth, spaceHeight = childLayout:GetSpaceWidthHeight();
					local flexGrow = childLayout:GetElementStyle()["flex-grow"] or 0;
					if (childLayout:IsFixedHeight() or flexGrow == 0) then
						offsetTop = offsetTop + spaceHeight;
					else 
						local autoHeight= remainHeight * flexGrow / line.flexGrow;
						offsetTop = offsetTop + spaceHeight + autoHeight;
						local width, height = childLayout:GetWidthHeight();
						childLayout:SetWidthHeight(width, height + autoHeight); 
						-- if (autoHeight ~= 0) then RelayoutChildrenElement(childLayout:GetElement(), "height_change") end

						-- 是否重新更新子布局
					end
				end
			else
                if (style["justify-content"] == "center") then 
                    offsetTop = remainHeight / 2; 
                elseif (style["justify-content"] == "flex-end") then 
                    offsetTop = remainHeight; 
				elseif (style["justify-content"] == "space-between") then 
					local gapCount = #(line.layouts) - 1;
					if (gapCount > 0) then VGap = remainHeight / gapCount end
                elseif (style["justify-content"] == "space-around") then 
					local gapCount = #(line.layouts) + 1;
					VGap = remainHeight / gapCount;
					offsetTop = VGap;
				end 
				UpdateChildLayoutPos(line);
			end
		else 
			UpdateChildLayoutPos(line);
        end
        -- print("FlexLayoutAdjustChildrenPosition:UpdateCol", offsetLeft, offsetTop, HGap, VGap);
        contentHeight = math.max(contentHeight, offsetTop - (style["justify-content"] == "space-around" and VGap or 0));
        offsetTop, VGap = 0, 0;
        offsetLeft = offsetLeft + line.width + HGap;
        contentWidth = math.max(contentWidth, offsetLeft - (style["align-items"] == "space-around" and HGap or 0));
    end

    self:SetRealContentWidthHeight(contentWidth, contentHeight);
end

return Layout;


